package karpiel.boguchwal.wojciech.przemek

object Launcher {
  def main(args: Array[String]): Unit = {
    val cfg = parseArgs(args.toList)
    if (cfg.showHelp || cfg.input.isEmpty) printHelp()
    else work(cfg.input.get, cfg.useCache,cfg.catchErr)
  }

  private def parseArgs(args: List[String], cfg: Config = Config()): Config = {
    args match {
      case Nil => cfg
      case "-h" :: t => parseArgs(t, cfg.copy(showHelp = true))
      case "--no-cache" ::t => parseArgs(t, cfg.copy(useCache = false))
      case "-f" :: fileName :: t => parseArgs(t, cfg.copy(input = Some(scala.io.Source.fromFile(fileName).mkString)))
      case "--xD" :: t => parseArgs(t, cfg.copy(catchErr = false))
      case xD => cfg.copy(input = Some(xD.mkString(" ")))
    }
  }

  private def work(input: String,useCache:Boolean, catchErr: Boolean): Unit = {
    if (catchErr)
      try {
        work(input,useCache)
      } catch {
        case e: PrzemekException => System.err.println("((NIE ZGADZA SIĘ, W KODZIE JEST BŁĄD)):\n" + e.msg)
          System.exit(-1)
      } else work(input,useCache)
  }

  private def work(input: String,useCache:Boolean): Unit = {
    println("Kod:\n\t" + input.replaceAll("\n", "\n\t"))
    implicit val cache: Cache = if (useCache) RealCache() else DummyCache
    val parsed = NoDepsParser.parse(input)
    implicit val ctx: Context = parsed.initalContext
    println("Kontekst jest git")
    if (!ctx.isEmpty) println("Kontekst:\n\t" + ctx.toStringQ.replaceAll("\n", "\n\t"))
    println("Ads: " + parsed.bruinizedExpr.prettyPrint)
    println("Znormalizowane: " + parsed.bruinizedExpr.normalized.prettyPrint)
    println("Typ: " + parsed.bruinizedExpr.inferType.prettyPrint)
  }

  private def printHelp(): Unit = {
    println(
      """Dzień dobry
        |Aktualnie zajmuje się sprawdzaniem typów.
        |Podaj coś to ci powiem jaki ma typ
        |np. polimorficza funkcja identycznościowa
        |(lambda (A (universe 0)) (lambda (x A) x))
        |albo użyta do tyou jednostkowego
        |((lambda (A (universe 0)) (lambda (x A) x)) unit)
        |a potem zaaplikowana do przedstawiciela typu jednostkowego
        |(((lambda (A (universe 0)) (lambda (x A) x)) unit) tt)
        |Fajne co nie?
        |Inna opcja to wczytanie pliku z kodem
        |-f example.prmk
      """.stripMargin)
  }

  private case class Config(input: Option[String] = None,
                            showHelp: Boolean = false,
                            catchErr: Boolean = true,
                            useCache:Boolean = true)

}
